/*
 * Copyright (C) 2009, 2010 M. Homs
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var ExceptionsTestCase = function() {

	this.testNestedExceptions = function() {

		try {
			throw JsUnitException("level-1", "here an error cause");
		} catch(e) {
			try {
				throw JsUnitException("level-2", "2", e);
			} catch(e) {
				assert.equals(
					"[JsUnitException] level-2 failure: 2"+
					"\n\tCaused by: [JsUnitException] level-1 failure: here an error cause",
					e
				);
			}
		}

		assert.equals(1, 1);
	};
};

var AssertionsTestCase = function() {

	this.testEquals = function() {

		assert.equals(1, 1);
		assert.equals(1, "1");

		assert.equals(true, true);

		assert.equals("t", "t");
		assert.equals(null, null);
		assert.equals(undefined, undefined);
		try {
			assert.equals(1, 2);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
			assert.equals(
				"[JsUnitException] equals failure: Expected: '1' (number), but obtained: '2' (number)",
				e.toString());
		}

		assert.equals(null, null);
		assert.equals(null, undefined);

		assert.equals("hi", "hi");
		assert.equals(5, 5);
		assert.notequals(5, 10);

		assert.equals( [], []);
		assert.equals( [ 1, 2 ], [ 1, 2 ]);
		assert.notequals( [ 1, 2 ], [ 2, 1 ]);
		assert.notequals( [ 1, 2 ], [ 1, 2, 3 ]);

		assert.equals({},{});
		assert.equals({a:1,b:2},{a:1,b:2});
		assert.equals({a:1,b:2},{b:2,a:1});
		assert.notequals({a:1,b:2},{a:1,b:3});

		assert.equals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}},{1:{name:"mhc",age:28}, 2:{name:"arb",age:26}});
		assert.notequals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}},{1:{name:"mhc",age:28}, 2:{name:"arb",age:27}});

		assert.equals(function(x){return x;},function(x){return x;});
		assert.notequals(function(x){return x;},function(y){return y+2;});
	};

	this.testStrictlyEquals = function() {

		assert.sequals(1, 1);
		assert.sequals("a", "a");
		assert.sequals(null, null);
		assert.sequals(undefined, undefined);
		try {
			assert.sequals(1, "1");
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}

		assert.sequals(null, null);
		assert.notsequals(null, undefined);

		assert.sequals("hi", "hi");
		assert.sequals(5, 5);
		assert.notsequals(5, 10);

		assert.sequals( [], []);
		assert.sequals( [ 1, 2 ], [ 1, 2 ]);
		assert.notsequals( [ 1, 2 ], [ 2, 1 ]);
		assert.notsequals( [ 1, 2 ], [ 1, 2, 3 ]);

		assert.sequals({},{});
		assert.sequals({a:1,b:2},{a:1,b:2});
		assert.sequals({a:1,b:2},{b:2,a:1});
		assert.notsequals({a:1,b:2},{a:1,b:3});

		assert.sequals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}},{1:{name:"mhc",age:28}, 2:{name:"arb",age:26}});
		assert.notsequals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}},{1:{name:"mhc",age:28}, 2:{name:"arb",age:27}});

		assert.sequals(function(x){return x;},function(x){return x;});
		assert.notsequals(function(x){return x;},function(y){return y+2;});
	};

	this.testFail = function() {

		try {
			assert.fail();
		} catch (e) {
			assert.equals(
				"[JsUnitFailureException] a fail(...) method executed, then a test condition is failed. message is: fail() method invoked, it means a test failure",
				e.toString());
		}
	};

	this.testNull = function() {

		assert.isNull(null);
		try {
			assert.isNull("jou");
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
		try {
			assert.isNull(undefined);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
	};

	this.testNotNull = function() {

		assert.notNull(2);
		assert.notNull("jou1");
		assert.notNull(undefined);
		try {
			assert.notNull(null);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
	};

	this.testDefined = function() {

		assert.isDefined(2);
		assert.isDefined("jou1");
		assert.isDefined(null);
		try {
			assert.isDefined(undefined);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
	};

	this.testIsUndefined = function() {

		assert.isUndefined(undefined);

		try {
			assert.isUndefined(3);
			assert.fail("jou1");
		} catch (e) {
			assert.isJsUnitException(e);
		}
		try {
			assert.isUndefined(null);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
	};

	this.testIsFunction = function() {

		assert.isFunction(function() {});

		try {
			assert.isFunction(null);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
		try {
			assert.isFunction("qwert");
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
	};

	this.testIsBoolean = function() {

		assert.isBoolean(true);
		assert.isBoolean(false);
		try {
			assert.isBoolean(null);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
		try {
			assert.isBoolean("qwert");
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
	};

	this.testIsString = function() {

		assert.isString("the qwertiest keyboard even built");
		try {
			assert.isString(null);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
		try {
			assert.isString(true);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
	};

	this.testIsNumber = function() {

		assert.isNumber(2);
		try {
			assert.isNumber(null);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
		try {
			assert.isNumber("qwert");
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
	};

	this.testIsTrue = function() {

		assert.isTrue(true);
		assert.isTrue("q" === "q");
		try {
			assert.isTrue(false);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
		try {
			assert.isTrue(null);
			assert.fail("qwert2");
		} catch (e) {
			assert.isJsUnitException(e);
		}
	};

	this.testIsFalse = function() {

		assert.isFalse(false);
		assert.isFalse("q" === "w");
		try {
			assert.isFalse(true);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
		try {
			assert.isFalse(null);
			assert.fail("qwert2");
		} catch (e) {
			assert.isJsUnitException(e);
		}
	};

	this.testIsArray = function() {

		assert.isArray( []);
		assert.isArray( [ 1, 2, 3 ]);
		assert.isArray( [ "a", "b", "c" ]);
		try {
			assert.isArray("hi");
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
		try {
			assert.isArray(null);
			assert.fail("qwert2");
		} catch (e) {
			assert.isJsUnitException(e);
		}
	};

	this.testNotNaN = function() {

		assert.notNaN(2 * 5);
		assert.notNaN(null);
		assert.notNaN(undefined);
		try {
			assert.notNaN(0 / 0);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
	};

	this.testIsNaN = function() {

		assert.isNaN(0 / 0);
		try {
			assert.isNaN(2 * 5);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
		try {
			assert.isNaN(null);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
	};

	this.testIsJsUnitException = function() {

		assert.isJsUnitException(JsUnitException("", ""));
		try {
			assert.isJsUnitException(new Array());
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
		try {
			assert.isJsUnitException(null);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
	};

	this.testSameType = function() {

		assert.sameType(0, 9);
		assert.sameType("a", "z");
		assert.sameType(function() {
		}, function() {
		});
		assert.sameType(true, false);
		assert.sameType(null, null);
		try {
			assert.sameType("a", 2);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
		try {
			assert.sameType(function() {
			}, 2);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
		try {
			assert.sameType(true, 2);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
		try {
			assert.sameType(null, undefined);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
	};

	this.testEqualsWithTolerance = function() {

		assert.equalsWithTolerance(1, 2, 1);
		assert.equalsWithTolerance(2, 1, 1);

		try {
			assert.equalsWithTolerance(1, 2, 0.5);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
		try {
			assert.equalsWithTolerance(null, null, null);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
	};

	this.testContains = function() {

		assert.contains( [ 1, 2, 3 ], 1);
		assert.contains( [ 1, 2, 3 ], 2);
		assert.contains( [ 1, 2, 3 ], 3);

		try {
			assert.contains( [ 1, 2, 3 ], 4);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}

		assert.contains({1:"one",2:"two",3:"three"}, "two");
		try {
			assert.contains({1:"one",2:"two",3:"three"}, 2);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
	};

	this.testHasLength = function() {

		assert.hasLength([], 0);
		assert.hasLength([ 1 ], 1);
		assert.hasLength([ 1, 2, 3 ], 3);

		try {
			assert.hasLength(null,null);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}

		try {
			assert.hasLength( [ 1, 2, 3 ], 4);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}

		assert.hasLength( {}, 0);
		assert.hasLength( {1:1}, 1);
		assert.hasLength( {1:1,2:2,3:3}, 3);

		try {
			assert.hasLength( {1:1,2:2,3:3}, 4);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
	};

	this.testHasProperty = function() {

		assert.hasProperty( [ 10, 20, 30 ], 0);
		assert.hasProperty( [ 10, 20, 30 ], 1);
		assert.hasProperty( [ 10, 20, 30 ], 2);

		try {
			assert.hasProperty( [ 10, 20, 30 ], 5);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}

		assert.hasProperty({"one":1,"two":2,"three":3}, "two");
		try {
			assert.hasProperty({"one":1,"two":2,"three":3}, "zero");
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
	};

	this.testArraySame = function() {

		assert.arraySame( [ 1, 2, 3 ], [ 1, 3, 2 ]);
		try {
			assert.arraySame( [ 1, 2, 3 ], [ 1, 2, 4 ]);
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
	};

	this.testRegexp = function() {

		assert.regexp(/^\d+$/, "1234567890");
		try {
			assert.regexp(/^\d+$/, "1234aaa890");
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
	};

	this.testNegate = function() {

		assert.negate(function() {
			assert.fail("");
		});
		try {
			assert.negate(function() {
			});
			assert.fail();
		} catch (e) {
			assert.isJsUnitException(e);
		}
	};

	// this.testFailure = function () {
	// assert.notNull(null);
	//	};

};

var TestCaseTest = {
	allOk : function() {
		this.beforeClass = function() {};
		this.before = function() {};
		this.testExample = function() {};
		this.after = function() {};
		this.afterClass = function() {};
	},
	failsBeforeClass : function() {
		this.beforeClass = function() {assert.fail("this is a fail() message");};
		this.before = function() {};
		this.testExample = function() {};
		this.after = function() {};
		this.afterClass = function() {};
	},
	failsBefore : function() {
		this.beforeClass = function() {};
		this.before = function() {assert.fail("this is a fail() message");};
		this.testExample = function() {};
		this.after = function() {};
		this.afterClass = function() {};
	},
	failsAfter : function() {
		this.beforeClass = function() {};
		this.before = function() {};
		this.testExample = function() {};
		this.after = function() {assert.fail("this is a fail() message");};
		this.afterClass = function() {};
	},
	failsAfterClass : function() {
		this.beforeClass = function() {};
		this.before = function() {};
		this.testExample = function() {};
		this.after = function() {};
		this.afterClass = function() {assert.fail("this is a fail() message");};
	},
	failsRegularTest : function() {
		this.beforeClass = function() {};
		this.before = function() {};
		this.testExample = function() {assert.fail("this is a fail() message");};
		this.after = function() {};
		this.afterClass = function() {};
	}
};

var TestCaseTestRunner = function(){
	this.testAllOk = function(){ runner.silentTestCaseRunner(new TestCaseTest.allOk(), true);};
	this.testFailsBeforeClass = function(){ assert.negate(function(){runner.silentTestCaseRunner(new TestCaseTest.failsBeforeClass(), true);});};
	this.testFailsBefore = function(){ assert.negate(function(){runner.silentTestCaseRunner(new TestCaseTest.failsBefore(), true);});};
	this.testFailsAfter = function(){ assert.negate(function(){runner.silentTestCaseRunner(new TestCaseTest.failsAfter(), true);});};
	this.testFailsAfterClass = function(){ assert.negate(function(){runner.silentTestCaseRunner(new TestCaseTest.failsAfterClass(), true);});};
	this.testFailsRegularTest = function(){ assert.negate(function(){runner.silentTestCaseRunner(new TestCaseTest.failsRegularTest(), true);});};
};



var FluentAssertionsTestcase = function() {

	this.testUndefined = function() {
		assert.fluent()
			.isUndefined()
			.notNull()
			.sameType(undefined)
			.equals(null)
			.notsequals(null)
			.sequals(undefined)
			;
	};
	this.testNumber10 = function() {
		assert.fluent(10)
			.isDefined()
			.notNull()
			.isNumber()
			.sameType(-1)
			.equals("10")
			.sequals(10)
			.notequals("5")
			.notsequals(5)
			.notNaN()
			.equalsWithTolerance(10.1, 0.2)
			;
	};
	this.testArray = function() {
		assert.fluent([ 1, 2, 3 ])
			.isArray()
			.isObject()
			.hasLength(3)
			.hasProperty(0)
			.hasProperty(1)
			.hasProperty(2)
			.contains(1)
			.contains(2)
			.contains(3)
			.arraySame([ 3, 2, 1 ])
			.notequals([ 3, 2, 1 ])
			;
	};
	this.testObject = function() {
		assert.fluent({"one":1,"two":2,"three":3})
			.isObject()
			.hasLength(3)
			.contains(1)
			.contains(2)
			.contains(3)
			.hasProperty("one")
			.hasProperty("two")
			.hasProperty("three")
			.sequals({"one":1,"two":2, "three":3})
			.equals({"two":2, "one":1, "three":3})
			;

		assert.fluent(this)
			.isObject()
			.hasLength(4)
			.hasProperty("testUndefined")
			.hasProperty("testNumber10")
			.hasProperty("testArray")
			.hasProperty("testObject")
			.sequals(this)
			.equals(this)
			;
	};
};

runner.silentTestCaseRunner(new AssertionsTestCase(), true);
runner.silentTestCaseRunner(new ExceptionsTestCase(), true);
runner.silentTestCaseRunner(new TestCaseTestRunner(), true);
runner.silentTestCaseRunner(new FluentAssertionsTestcase(), true);
